﻿namespace Fine.Collections.Intf
{
    /// <summary>
    /// A little structure that is returned from Find methods of Fine Collections.
    /// Value object.
    /// </summary>
    /// <typeparam name="T">type of an item.</typeparam>
    /// <seealso cref="SearchResults{T}"/>
    public interface SearchResult<out T>
    {
        /// <summary>
        /// Item that been found.
        /// Or <i>default(T)</i> if not found.
        /// </summary>
        T Item { get; }

        /// <summary>
        /// Determines whether the requested item was found.
        /// </summary>
        bool Found { get; }
    }


    /// <summary>
    /// Search results factory.
    /// </summary>
    /// <typeparam name="T">type of an item.</typeparam>
    /// <seealso cref="SearchResult{T}"/>
    public static class SearchResults<T>
    {
        /// <summary>
        /// Returns the successfull result with found item.
        /// </summary>
        /// <param name="item">found item.</param>
        /// <returns>successfull search result.</returns>
        /// <seealso cref="NotFound"/>
        public static SearchResult<T> Found(T item)
        {
            return new SearchFound<T>(item);
        }


        /// <summary>
        /// Returns the unsuccessfull (not found) search result.
        /// </summary>
        /// <returns>unsuccessfull search result.</returns>
        /// <seealso cref="Found"/>
        public static SearchResult<T> NotFound()
        {
            return notFound;
        }


        private static readonly SearchResult<T> notFound = 
            new SearchNotFound<T>();
    }


    internal sealed class SearchFound<T> : SearchResult<T>
    {
        private readonly T item;

        /// <summary>
        /// Creates an instance of successfull search result.
        /// </summary>
        /// <param name="item">found item.</param>
        internal SearchFound(T item)
        {
            this.item = item;
        }


        public T Item
        {
            get { return  item; }
        }

        public bool Found
        {
            get { return true; }
        }


        public override int GetHashCode()
        {
            return item != null ? item.GetHashCode() : 0;
        }


        public override string ToString()
        {
            return item != null ? item.ToString() : "";
        }
    }


    internal sealed class SearchNotFound<T> : SearchResult<T>
    {
        public T Item
        {
            get { return  default(T); }
        }

        public bool Found
        {
            get { return false; }
        }

        public override string ToString()
        {
            return "";
        }


        public override int GetHashCode()
        {
            return 0;
        }
    }
}
